import {
  SetupContext as VueSetupContext,
  VNode,
  PropType as VuePropType,
} from "vue";

/**
 * 这个工具主要作用就是为了把 js 逻辑和 html 模板分开写
 */

export type PropType<T> = VuePropType<T>;

export type SetupContext<
  Emits = any,
  Expose = any,
  Slots = any
> = VueSetupContext<Emits> & {
  emits: Emits;
  expose: (exposed?: Expose) => void;
  slots: Slots;
  ctx: VueSetupContext<Emits>;
};

type Data = Record<string, unknown>;

type DefaultFactory<T> = (props: Data) => T | null | undefined;

export interface PropOptions<T = any, D = T> {
  type: VuePropType<T>;
  required?: boolean;
  default?: D | DefaultFactory<D> | null | undefined;
  validator?(value: unknown): boolean;
}

export type Props = Record<string, PropOptions>;

type PropTypeGenericityType<T extends VuePropType<unknown>> =
  T extends VuePropType<infer R> ? R : any;

export type PropsType<
  T extends { [key in string]: { type: VuePropType<unknown> } }
> = {
  [k in keyof T]: PropTypeGenericityType<T[k]["type"]>;
};

/**
 * 相对于 vue 文件的 script 标签
 */
export function Script<State = any>(
  handleScript?: (props: any, ctx: any) => State
) {
  return {
    setup: handleScript,
    /**
     * 相对于 vue 文件的 template 标签
     */
    Template: function (handleTemplate: (this: State, state: State) => VNode) {
      function render(props: any, ctx: any) {
        const state = handleScript ? handleScript(props, ctx) : {};
        return handleTemplate.bind(state as State, state as State);
      }

      function setup(props: any, ctx: any) {
        return render(props, ctx);
      }

      return {
        setup,
        render: handleTemplate,
      };
    },
  };
}
